home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / opt / pinstaller / GLIArchitectureTemplate.py < prev    next >
Text File  |  2006-05-24  |  64KB  |  1,274 lines

  1. """
  2. # Copyright 1999-2005 Gentoo Foundation
  3. # This source code is distributed under the terms of version 2 of the GNU
  4. # General Public License as published by the Free Software Foundation, a copy
  5. # of which can be found in the main directory of this project.
  6. Gentoo Linux Installer
  7.  
  8. $Id: GLIArchitectureTemplate.py,v 1.262 2006/02/10 04:00:20 agaffney Exp $
  9.  
  10. The ArchitectureTemplate is largely meant to be an abstract class and an 
  11. interface (yes, it is both at the same time!). The purpose of this is to create 
  12. subclasses that populate all the methods with working methods for that architecture. 
  13. The only definitions that are filled in here are architecture independent. 
  14.  
  15. """
  16.  
  17. import GLIUtility, GLILogger, os, string, sys, shutil, re, time
  18. import GLIPortage
  19. from GLIException import *
  20.  
  21. class ArchitectureTemplate:
  22.     ##
  23.     # Initialization of the ArchitectureTemplate.  Called from some other arch template.
  24.     # @param selfconfiguration=None    A Client Configuration
  25.     # @param install_profile=None      An Install Profile
  26.     # @param client_controller=None    Client Controller.  not same as configuration.
  27.     def __init__(self,configuration=None, install_profile=None, client_controller=None):
  28.         self._client_configuration = configuration
  29.         self._install_profile = install_profile
  30.         self._cc = client_controller
  31.  
  32.         # This will get used a lot, so it's probably
  33.         # better to store it in a variable than to call
  34.         # this method 100000 times.
  35.         self._chroot_dir = self._client_configuration.get_root_mount_point()
  36.         self._logger = GLILogger.Logger(self._client_configuration.get_log_file())
  37.         self._compile_logfile = "/tmp/compile_output.log"
  38.         self._debug = self._client_configuration.get_verbose()
  39.  
  40.         self._portage = GLIPortage.GLIPortage(self._chroot_dir, self._install_profile.get_grp_install(), self._logger, self._debug, self._cc, self._compile_logfile)
  41.  
  42.         # This will cleanup the logfile if it's a dead link (pointing
  43.         # to the chroot logfile when partitions aren't mounted, else
  44.         # no action needs to be taken
  45.  
  46.         if os.path.islink(self._compile_logfile) and not os.path.exists(self._compile_logfile):
  47.             os.unlink(self._compile_logfile)
  48.  
  49.         # cache the list of successfully mounted swap devices here
  50.         self._swap_devices = []
  51.  
  52.         # These must be filled in by the subclass. _steps is a list of
  53.         # functions, that will carry out the installation. They must be
  54.         # in order.
  55.         #
  56.         # For example, self._steps might be: [preinstall, stage1, stage2, stage3, postinstall],
  57.         # where each entry is a function (with no arguments) that carries out the desired actions.
  58.         # Of course, steps will be different depending on the install_profile
  59.         
  60.         self._architecture_name = "generic"
  61.         self._install_steps = [
  62.             { 'function': self.partition, 'name': "Partition", 'modes': ("normal", "stage4") },
  63.             { 'function': self.mount_local_partitions, 'name': "Mount local partitions", 'modes': ("normal", "stage4") },
  64.             { 'function': self.mount_network_shares, 'name': "Mount network (NFS) shares", 'modes': ("normal", "stage4") },
  65.             { 'function': self.unpack_stage_tarball, 'name': "Copying filesystem", 'modes': ("normal", "stage4", "chroot") },
  66.             { 'function': self.update_config_files, 'name': "Updating config files", 'modes': ("normal", "chroot") },
  67.             { 'function': self.configure_make_conf, 'name': "Configure /etc/make.conf", 'modes': ("normal", "chroot") },
  68.             { 'function': self.prepare_chroot, 'name': "Preparing chroot", 'modes': ("normal", "stage4", "chroot") },
  69.             { 'function': self.install_portage_tree, 'name': "Syncing the Portage tree", 'modes': ("normal", "chroot") },
  70.             { 'function': self.stage1, 'name': "Performing bootstrap", 'modes': ("normal", "chroot") },
  71.             { 'function': self.stage2, 'name': "Performing 'emerge system'", 'modes': ("normal", "chroot") },
  72.             { 'function': self.set_root_password, 'name': "Set the root password", 'modes': ("normal", "chroot") },
  73.             { 'function': self.set_timezone, 'name': "Setting timezone", 'modes': ("normal", "chroot") },
  74.             { 'function': self.emerge_kernel_sources, 'name': "Emerge kernel sources", 'modes': ("normal", "chroot") },
  75.             { 'function': self.build_kernel, 'name': "Building kernel", 'modes': ("normal", "chroot") },
  76.             { 'function': self.install_distcc, 'name': "Install distcc", 'modes': ("normal", "chroot") },
  77.             { 'function': self.install_mta, 'name': "Installing MTA", 'modes': ("normal", "chroot") },
  78.             { 'function': self.install_logging_daemon, 'name': "Installing system logger", 'modes': ("normal", "chroot") },
  79.             { 'function': self.install_cron_daemon, 'name': "Installing Cron daemon", 'modes': ("normal", "chroot") },
  80.             { 'function': self.install_filesystem_tools, 'name': "Installing filesystem tools", 'modes': ("normal", "chroot") },
  81.             { 'function': self.setup_network_post, 'name': "Configuring post-install networking", 'modes': ("normal", "chroot") },
  82.             { 'function': self.install_bootloader, 'name': "Configuring and installing bootloader", 'modes': ("normal", "chroot") },
  83.             { 'function': self.setup_and_run_bootloader, 'name': "Setting up and running bootloader", 'modes': ( "normal", "stage4") },
  84.             { 'function': self.update_config_files, 'name': "Re-Updating config files", 'modes': ("normal", "chroot") },
  85. #            { 'function': self.configure_rc_conf, 'name': "Updating /etc/rc.conf", 'modes': ("normal", "stage4", "chroot") },
  86.             { 'function': self.set_users, 'name': "Add additional users.", 'modes': ("normal", "chroot") },
  87.             { 'function': self.install_packages, 'name': "Installing additional packages.", 'modes': ("normal", "chroot") },
  88.             # services for startup need to come after installing extra packages
  89.             # otherwise some of the scripts will not exist.
  90.             { 'function': self.set_services, 'name': "Setting up services for startup", 'modes': ("normal", "chroot") },
  91.             { 'function': self.run_post_install_script, 'name': "Running custom post-install script", 'modes': ("normal", "stage4", "chroot") },
  92.             { 'function': self.finishing_cleanup, 'name': "Cleanup and unmounting local filesystems.", 'modes': ("normal", "stage4", "chroot") }
  93.         ]
  94.  
  95.  
  96.     ##
  97.     # Returns the steps and their comments in an array
  98.     def get_install_steps(self):
  99.         return self._install_steps
  100.  
  101.     ##
  102.     # Tells the frontend something
  103.     # @param type type of data
  104.     # @param data the data itself.  usually a number.
  105.     def notify_frontend(self, type, data):
  106.         self._cc.addNotification(type, data)
  107.  
  108.     # It is possible to override these methods in each Arch Template.
  109.     # It might be necessary to do so, if the arch needs something 'weird'.
  110.  
  111.     ##
  112.     # Private function to add a /etc/init.d/ script to the given runlevel in the chroot environement
  113.     # @param script_name the script to be added
  114.     # @param runlevel="default" the runlevel to add to
  115.     def _add_to_runlevel(self, script_name, runlevel="default"):
  116.         if not GLIUtility.is_file(self._chroot_dir + '/etc/init.d/' + script_name):
  117.             #raise GLIException("RunlevelAddError", 'fatal', '_add_to_runlevel', "Failure adding " + script_name + " to runlevel " + runlevel + "!")
  118.             #This is not a fatal error.  If the init script is important it will exist.
  119.             self._logger.log("ERROR! Failure adding" + script_name + " to runlevel " + runlevel + " because it was not found!")
  120.             if self._debug:    self._logger.log("DEBUG: running rc-update add " + script_name + " " + runlevel + " in chroot.")
  121.         status = GLIUtility.spawn("rc-update add " + script_name + " " + runlevel, display_on_tty8=True, chroot=self._chroot_dir, logfile=self._compile_logfile, append_log=True)
  122.         if not GLIUtility.exitsuccess(status):
  123.             #raise GLIException("RunlevelAddError", 'fatal', '_add_to_runlevel', "Failure adding " + script_name + " to runlevel " + runlevel + "!")
  124.             #Again, an error here will not prevent a new system from booting.  But it is important to log the error.
  125.             self._logger.log("ERROR! Could not add " + script_name + " to runlevel " + runlevel + ". returned a bad status code.")
  126.         else:
  127.             self._logger.log("Added "+script_name+" to runlevel "+runlevel)
  128.  
  129.     ##
  130.     # Private Function.  Will return a list of packages to be emerged for a given command.  Not yet used.
  131.     # @param cmd full command to run ('/usr/portage/scripts/bootstrap.sh --pretend' or 'emerge -p system')
  132.     def _get_packages_to_emerge(self, cmd):
  133.         if self._debug:    self._logger.log("DEBUG: _get_packages_to_emerge() called with '%s'" % cmd)
  134.         return GLIUtility.spawn(cmd + r" 2>/dev/null | grep -e '\[ebuild' | sed -e 's:\[ebuild .\+ \] ::' -e 's: \[.\+\] ::' -e 's: \+$::'", chroot=self._chroot_dir, return_output=True)[1].strip().split("\n")
  135.  
  136.     ##
  137.     # Private Function.  Will emerge a given package in the chroot environment.
  138.     # @param package package to be emerged
  139.     # @param binary=False defines whether to try a binary emerge (if GRP this gets ignored either way)
  140.     # @param binary_only=False defines whether to only allow binary emerges.
  141.     def _emerge(self, package, binary=True, binary_only=False):
  142.         #Error checking of this function is to be handled by the parent function.
  143. #        self._logger.log("_emerge() called with: package='%s', binary='%s', binary_only='%s', grp_install='%s'" % (package, str(binary), str(binary_only), str(self._install_profile.get_grp_install())))
  144.         # now short-circuit for GRP
  145.         if self._install_profile.get_grp_install():
  146.             cmd="emerge -k " + package
  147.         # now normal installs
  148.         else:
  149.             if binary_only:
  150.                 cmd="emerge -K " + package
  151.             elif binary:
  152.                 cmd="emerge -k " + package
  153.             else:
  154.                 cmd="emerge " + package
  155.  
  156.         self._logger.log("Calling emerge: "+cmd)
  157.         return GLIUtility.spawn(cmd, display_on_tty8=True, chroot=self._chroot_dir, logfile=self._compile_logfile, append_log=True)
  158.  
  159.     ##
  160.     # Private Function.  Will edit a config file and insert a value or two overwriting the previous value
  161.     # (actually it only just comments out the old one)
  162.     # @param filename             file to be edited
  163.     # @param newvalues             a dictionary of VARIABLE:VALUE pairs
  164.     # @param delimeter='='             what is between the key and the value
  165.     # @param quotes_around_value=True     whether there are quotes around the value or not (ex. "local" vs. localhost)
  166.     # @param only_value=False        Ignore the keys and output only a value.
  167.     # @param create_file=True        Create the file if it does not exist.
  168.     def _edit_config(self, filename, newvalues, delimeter='=', quotes_around_value=True, only_value=False,create_file=True):
  169.         # don't use 'file' as a normal variable as it conflicts with the __builtin__.file
  170.         newvalues = newvalues.copy()
  171.         if self._debug: self._logger.log("DEBUG: _edit_config() called with " + str(newvalues)+" and flags: "+delimeter + "quotes: "+str(quotes_around_value)+" value: "+str(only_value))
  172.         if GLIUtility.is_file(filename):
  173.             f = open(filename)
  174.             contents = f.readlines()
  175.             f.close()
  176.         elif create_file:
  177.             contents = []
  178.         else:
  179.             raise GLIException("NoSuchFileError", 'notice','_edit_config',filename + ' does not exist!')
  180.     
  181.         for key in newvalues.keys():
  182.             newline = ""
  183.             if key == "SPACER":
  184.                 newline = "\n"
  185.             elif key == "COMMENT":
  186.                 newline = '# ' + newvalues[key] + "\n"
  187.             elif newvalues[key] == "##comment##" or newvalues[key] == "##commented##":
  188.                 newline = '#' + key + delimeter + '""' + "\n"
  189.             else:
  190.                 if quotes_around_value:
  191.                     newvalues[key] = '"' + newvalues[key] + '"'
  192.                 #Only the printing of values is required.
  193.                 if only_value:
  194.                     newline = newvalues[key] + "\n"
  195.                 else:
  196.                     newline = key + delimeter + newvalues[key] + "\n"
  197.             add_at_line = len(contents)
  198.             for i in range(len(contents)):
  199.                 if newline == contents[i]:
  200.                     break
  201.                 if contents[i].startswith(key + delimeter):
  202.                     contents[i] = "#" + contents[i]
  203.                     add_at_line = i + 1
  204.             else:
  205.                 contents.insert(add_at_line, newline)
  206.         if self._debug: self._logger.log("DEBUG: Contents of file "+filename+": "+str(contents))
  207.         f = open(filename,'w')
  208.         f.writelines(contents)
  209.         f.flush()
  210.         f.close()
  211.         self._logger.log("Edited Config file "+filename)
  212.  
  213.     ##
  214.     # Stage 1 install -- bootstraping the system
  215.     # If we are doing a stage 1 install, then bootstrap 
  216.     def stage1(self):
  217.         if self._install_profile.get_install_stage() == 1:
  218.             self._logger.mark()
  219.             self._logger.log("Starting bootstrap.")
  220.             pkgs = self._get_packages_to_emerge("/usr/portage/scripts/bootstrap.sh --pretend")
  221.             if self._debug: self._logger.log("DEBUG: Packages to emerge: "+str(pkgs)+". Now running bootstrap.sh")
  222.             exitstatus = GLIUtility.spawn("/usr/portage/scripts/bootstrap.sh", chroot=self._chroot_dir, display_on_tty8=True, logfile=self._compile_logfile, append_log=True)
  223.             if not GLIUtility.exitsuccess(exitstatus):
  224.                 raise GLIException("Stage1Error", 'fatal','stage1', "Bootstrapping failed!")
  225.             self._logger.log("Bootstrap complete.")
  226.     ##
  227.     # Stage 2 install -- emerge -e system
  228.     # If we are doing a stage 1 or 2 install, then emerge system
  229.     def stage2(self):
  230.         if self._install_profile.get_install_stage() in [ 1, 2 ]:
  231.             self._logger.mark()
  232.             self._logger.log("Starting emerge system.")
  233.             pkgs = self._get_packages_to_emerge("emerge -p system")  #currently quite the useless
  234.             if self._debug: self._logger.log("DEBUG: Packages to emerge: "+str(pkgs)+"/ Now running emerge --emptytree system")
  235.             exitstatus = self._emerge("--emptytree system")
  236.             if not GLIUtility.exitsuccess(exitstatus):
  237.                 raise GLIException("Stage2Error", 'fatal','stage2', "Building the system failed!")
  238.             self._logger.log("Emerge system complete.")
  239.  
  240.     ##
  241.     # Unpacks the stage tarball that has been specified in the profile (it better be there!)
  242.     def unpack_stage_tarball(self):
  243.         # This is the copying done for mpentoo
  244.         if not os.path.isdir(self._chroot_dir):
  245.             if self._debug: self._logger.log("DEBUG: making the chroot dir:"+self._chroot_dir)
  246.             os.makedirs(self._chroot_dir)
  247.         
  248.         # stage3 generation code here 15 pkgs
  249.         dircd= [ "dev", "proc", "tmp", "mnt", "sys" ]
  250.         dirlive = [ "bin", "boot", "etc", "home", "lib", "opt", "root", "sbin", "usr" , "var" ]
  251.         
  252.         for i in range(len(dirlive)) :
  253.             self.notify_frontend("progress", (float(i) / (16), "Copying " + dirlive[i]))
  254.             GLIUtility.spawn("cp -a /" + dirlive[i] + " " + self._chroot_dir + "/" )
  255.         self.notify_frontend("progress", (float(15) / (16), "Finishing"))
  256.         for i in range(len(dircd)) :
  257.             self.notify_frontend("progress", (float(i+10) / (16), "Copying " + dircd[i]))
  258.             GLIUtility.spawn("cp -a /mnt/livecd/" + dircd[i] + " " + self._chroot_dir + "/" )
  259.         GLIUtility.spawn("mv " + self._chroot_dir + " " + "/etc/init.d/halt.sh.orig" + self._chroot_dir + "/etc/init.d/halt.sh")
  260.         GLIUtility.spawn("mv " + self._chroot_dir + " " + "/etc/init.d/fstab.orig" + self._chroot_dir + "/etc/init.d/fstab")
  261.         GLIUtility.spawn("cp -a /etc/inittab.orig " + self._chroot_dir + "/etc/inittab")
  262.         GLIUtility.spawn("cp -a /mnt/cdrom/isolinux/pentoo* " + self._chroot_dir + "/boot/")
  263.         GLIUtility.spawn("echo '' > " + self._chroot_dir + "/etc/conf.d/local.start")
  264.         GLIUtility.spawn("echo '' > " + self._chroot_dir + "/etc/conf.d/local.stop")
  265.         chrootscript = r"""
  266.         #!/bin/bash
  267.         env-update
  268.         source /etc/profile
  269.         """
  270.         dirlive.__len__()
  271.         script = open(self._chroot_dir + "/tmp/extrastuff.sh", "w")
  272.         script.write(chrootscript)
  273.         script.close()
  274.         GLIUtility.spawn("chmod 755 /tmp/extrastuff.sh && /tmp/extrastuff.sh", chroot=self._chroot_dir, display_on_tty8=True, logfile=self._compile_logfile, append_log=True)
  275.         GLIUtility.spawn("rm -rf /var/tmp/portage/*", chroot=self._chroot_dir)
  276.         self.notify_frontend("progress", (1, "Done"))
  277.         self._logger.log("Filesystem was copied successfully")
  278.  
  279.     ##
  280.     # Prepares the Chroot environment by copying /etc/resolv.conf and mounting proc and dev
  281.     def prepare_chroot(self):
  282.         # Copy resolv.conf to new env
  283.         try:
  284.             if self._debug: self._logger.log("DEBUG: copying /etc/resolv.conf over.")
  285.             shutil.copy("/etc/resolv.conf", self._chroot_dir + "/etc/resolv.conf")
  286.         except:
  287.             pass
  288.         if self._debug: self._logger.log("DEBUG: mounting proc")
  289.         ret = GLIUtility.spawn("mount -t proc none "+self._chroot_dir+"/proc")
  290.         if not GLIUtility.exitsuccess(ret):
  291.             raise GLIException("MountError", 'fatal','prepare_chroot','Could not mount /proc')
  292.         bind_mounts = [ '/dev' ]
  293.         uname = os.uname()
  294.         if uname[0] == 'Linux' and uname[2].split('.')[1] == '6':
  295.             bind_mounts.append('/sys')
  296.         if self._debug: self._logger.log("DEBUG: bind-mounting " + ", ".join(bind_mounts))
  297.         for mount in bind_mounts:
  298.             ret = GLIUtility.spawn('mount -o bind %s %s%s' % (mount,self._chroot_dir,mount))
  299.             if not GLIUtility.exitsuccess(ret):
  300.                 raise GLIException("MountError", 'fatal','prepare_chroot','Could not mount '+mount)
  301.         if self._debug: self._logger.log("DEBUG: copying logfile to new system!")
  302.         GLIUtility.spawn("mv " + self._compile_logfile + " " + self._chroot_dir + self._compile_logfile + " && ln -s " + self._chroot_dir + self._compile_logfile + " " + self._compile_logfile)
  303.         self._logger.log("Chroot environment ready.")
  304.  
  305.     ##
  306.     # Installs a list of packages specified in the profile. Will install any extra software!
  307.     # In the future this function will lead to better things.  It may even wipe your ass for you.
  308.     def install_packages(self):
  309.         installpackages = self._install_profile.get_install_packages()
  310. #        if installpackages:
  311. #            pkglist = self._portage.get_deps(" ".join(installpackages))
  312. #            if self._debug: self._logger.log("install_packages(): pkglist is " + str(pkglist))
  313. #            for i, pkg in enumerate(pkglist):
  314. #                if self._debug: self._logger.log("install_packages(): processing package " + pkg)
  315. #                self.notify_frontend("progress", (float(i) / len(pkglist), "Emerging " + pkg + " (" + str(i) + "/" + str(len(pkglist)) + ")"))
  316. #                if not self._portage.get_best_version_vdb("=" + pkg):
  317. #                    status = self._emerge("=" + pkg)
  318. #                    if not GLIUtility.exitsuccess(status):
  319. #                        raise GLIException("ExtraPackagesError", "fatal", "install_packages", "Could not emerge " + pkg + "!")
  320. #                else:
  321. #                    try:
  322. #                        self._portage.copy_pkg_to_chroot(pkg)
  323. #                    except:
  324. #                        raise GLIException("ExtraPackagesError", "fatal", "install_packages", "Could not emerge " + pkg + "!")
  325. #            self._portage.emerge(installpackages)
  326.  
  327.         if GLIUtility.is_file(self._chroot_dir + "/etc/X11"):
  328.             # Copy the xorg.conf from the LiveCD if they installed xorg-x11
  329.             exitstatus = GLIUtility.spawn("cp /etc/X11/xorg.conf " + self._chroot_dir + "/etc/X11/xorg.conf")
  330.             if not GLIUtility.exitsuccess(exitstatus):
  331.                 self._logger.log("Could NOT copy the xorg configuration from the livecd to the new system!")
  332.             else:
  333.                 self._logger.log("xorg.conf copied to new system.  X should be ready to roll!")
  334.         if GLIUtility.is_file(self._chroot_dir + "/etc/X11/gdm/gdm.conf"):
  335.             GLIUtility.spawn("cp -f /etc/X11/gdm/gdm.conf.old " + self._chroot_dir + "/etc/X11/gdm/gdm.conf")
  336.  
  337.     ##
  338.     # Will set the list of services to runlevel default.  This is a temporary solution!
  339.     def set_services(self):
  340.         services = self._install_profile.get_services()
  341.         for service in services:
  342.             self._add_to_runlevel(service)
  343.                 
  344.     ##
  345.     # Will grab partition info from the profile and mount all partitions with a specified mountpoint (and swap too)
  346.     def mount_local_partitions(self):
  347.         #{   1: {   'end': 1999871,          'format': False,            'mb': 0,
  348.         #'mountopts': '',   'mountpoint': '',   'start': 63,    'type': 'linux-swap'},
  349.         #2: {   'end': 240121727, 'format': False,  'mb': 0, 'mountopts': '',  
  350.         #'mountpoint': '',  'start': 1999872,  'type': 'ext3'}}
  351.         
  352.         parts = self._install_profile.get_partition_tables()
  353.         parts_to_mount = {}
  354.         for device in parts:
  355.             tmp_partitions = parts[device].get_install_profile_structure()
  356.             tmp_minor = -1
  357.             for minor in tmp_partitions:
  358.                 if not tmp_partitions[minor]['type'] == "free":
  359.                     tmp_minor = minor
  360.                     break
  361.             time.sleep(1)
  362.             if tmp_minor == -1: continue
  363.             # now sleep until it exists
  364.             while not GLIUtility.is_file(parts[device].get_device() + str(tmp_minor)):
  365.                 if self._debug: self._logger.log("DEBUG: Waiting for device node " + parts[device].get_device() + str(tmp_minor) + " to exist...")
  366.                 time.sleep(1)
  367.             # one bit of extra sleep is needed, as there is a blip still
  368.             time.sleep(1)
  369.             for partition in tmp_partitions:
  370.                 mountpoint = tmp_partitions[partition]['mountpoint']
  371.                 mountopts = tmp_partitions[partition]['mountopts']
  372.                 minor = str(int(tmp_partitions[partition]['minor']))
  373.                 partition_type = tmp_partitions[partition]['type']
  374.                 if mountpoint:
  375.                     if mountopts:
  376.                         mountopts = "-o " + mountopts + " "
  377.                     if partition_type:
  378.                         if partition_type == "fat32" or partition_type == "fat16": partition_type = "vfat"
  379.                         partition_type = "-t " + partition_type + " "
  380.                     parts_to_mount[mountpoint]= (mountopts, partition_type, device + minor)
  381.                     
  382.                 if partition_type == "linux-swap":
  383.                     ret = GLIUtility.spawn("swapon " + device + minor)
  384.                     if not GLIUtility.exitsuccess(ret):
  385.                         self._logger.log("ERROR! : Could not activate swap (" + device + minor + ")!")
  386.                     else:
  387.                         self._swap_devices.append(device + minor)
  388.         sorted_list = parts_to_mount.keys()
  389.         sorted_list.sort()
  390.         
  391.         if not GLIUtility.is_file(self._chroot_dir):
  392.             if self._debug: self._logger.log("DEBUG: making the chroot dir")
  393.             exitstatus = GLIUtility.spawn("mkdir -p " + self._chroot_dir)
  394.             if not GLIUtility.exitsuccess(exitstatus):
  395.                 raise GLIException("MkdirError", 'fatal','mount_local_partitions', "Making the ROOT mount point failed!")
  396.             else:
  397.                 self._logger.log("Created root mount point")
  398.         for mountpoint in sorted_list:
  399.             mountopts = parts_to_mount[mountpoint][0]
  400.             partition_type = parts_to_mount[mountpoint][1]
  401.             partition = parts_to_mount[mountpoint][2]
  402.             if not GLIUtility.is_file(self._chroot_dir + mountpoint):
  403.                 if self._debug: self._logger.log("DEBUG: making mountpoint: "+mountpoint)
  404.                 exitstatus = GLIUtility.spawn("mkdir -p " + self._chroot_dir + mountpoint)
  405.                 if not GLIUtility.exitsuccess(exitstatus):
  406.                     raise GLIException("MkdirError", 'fatal','mount_local_partitions', "Making the mount point failed!")
  407.                 else:
  408.                     self._logger.log("Created mountpoint " + mountpoint)
  409.             ret = GLIUtility.spawn("mount " + partition_type + mountopts + partition + " " + self._chroot_dir + mountpoint, display_on_tty8=True, logfile=self._compile_logfile, append_log=True)
  410.             if not GLIUtility.exitsuccess(ret):
  411.                 raise GLIException("MountError", 'fatal','mount_local_partitions','Could not mount a partition')
  412.             # double check in /proc/mounts
  413.             # This current code doesn't work and needs to be fixed, because there is a case that it is needed for - robbat2
  414.             #ret, output = GLIUtility.spawn('awk \'$2 == "%s" { print "Found" }\' /proc/mounts | head -n1' % (self._chroot_dir + mountpoint), display_on_tty8=True, return_output=True)
  415.             #if output.strip() != "Found":
  416.             #    raise GLIException("MountError", 'fatal','mount_local_partitions','Could not mount a partition (failed in double-check)')
  417.             self._logger.log("Mounted mountpoint: " + mountpoint)
  418.  
  419.     ##
  420.     # Mounts all network shares to the local machine
  421.     def mount_network_shares(self):
  422.         """
  423.         <agaffney> it'll be much easier than mount_local_partitions
  424.         <agaffney> make sure /etc/init.d/portmap is started
  425.         <agaffney> then mount each one: mount -t nfs -o <mountopts> <host>:<export> <mountpoint>
  426.         """
  427.         nfsmounts = self._install_profile.get_network_mounts()
  428.         for netmount in nfsmounts:
  429.             if netmount['type'] == "NFS" or netmount['type'] == "nfs":
  430.                 mountopts = netmount['mountopts']
  431.                 if mountopts:
  432.                     mountopts = "-o " + mountopts
  433.                 host = netmount['host']
  434.                 export = netmount['export']
  435.                 mountpoint = netmount['mountpoint']
  436.                 if not GLIUtility.is_file(self._chroot_dir + mountpoint):
  437.                     exitstatus = GLIUtility.spawn("mkdir -p " + self._chroot_dir + mountpoint)
  438.                     if not GLIUtility.exitsuccess(exitstatus):
  439.                         raise GLIException("MkdirError", 'fatal','mount_network_shares', "Making the mount point failed!")
  440.                     else:
  441.                         if self._debug: self._logger.log("DEBUG: mounting nfs mount")
  442.                 ret = GLIUtility.spawn("mount -t nfs " + mountopts + " " + host + ":" + export + " " + self._chroot_dir + mountpoint, display_on_tty8=True, logfile=self._compile_logfile, append_log=True)
  443.                 if not GLIUtility.exitsuccess(ret):
  444.                     raise GLIException("MountError", 'fatal','mount_network_shares','Could not mount an NFS partition')
  445.                 self._logger.log("Mounted netmount at mountpoint: " + mountpoint)
  446.             else:
  447.                 self._logger.log("Netmount type " + netmount['type'] + " not supported...skipping " + netmount['mountpoint'])
  448.  
  449.  
  450.     ##
  451.     # Configures the new /etc/make.conf
  452.     def configure_make_conf(self):
  453.         # Get make.conf options
  454.         make_conf = self._install_profile.get_make_conf()
  455.         
  456.  
  457.     ##
  458.     # This will get/update the portage tree.  If you want to snapshot or mount /usr/portage use "custom".
  459.     def install_portage_tree(self):
  460.         # Check the type of portage tree fetching we'll do
  461.         # If it is custom, follow the path to the custom tarball and unpack it
  462.  
  463.         # This is a hack to copy the LiveCD's rsync into the chroot since it has the sigmask patch
  464.         if self._debug: self._logger.log("DEBUG: Doing the hack where we copy the LiveCD's rsync into the chroot since it has the sigmask patch")
  465.         GLIUtility.spawn("cp -a /usr/bin/rsync " + self._chroot_dir + "/usr/bin/rsync")
  466.         GLIUtility.spawn("cp -a /usr/lib/libpopt* " + self._chroot_dir + "/usr/lib")
  467.         
  468.         sync_type = self._install_profile.get_portage_tree_sync_type()
  469.         if sync_type == "snapshot" or sync_type == "custom": # Until this is finalized
  470.         
  471.             # Get portage tree info
  472.             portage_tree_snapshot_uri = self._install_profile.get_portage_tree_snapshot_uri()
  473.             if portage_tree_snapshot_uri:
  474.                 # Fetch and unpack the tarball
  475.                 if self._debug: self._logger.log("DEBUG: grabbing custom snapshot uri: "+portage_tree_snapshot_uri)
  476.                 GLIUtility.fetch_and_unpack_tarball(portage_tree_snapshot_uri, self._chroot_dir + "/usr/", self._chroot_dir + "/", cc=self._cc)
  477.                 if GLIUtility.is_file("/usr/livecd/metadata.tar.bz2"):
  478.                     GLIUtility.fetch_and_unpack_tarball("/usr/livecd/metadata.tar.bz2", self._chroot_dir + "/", self._chroot_dir + "/", cc=self._cc)
  479.             self._logger.log("Portage tree install was custom.")
  480.         elif sync_type == "sync":
  481.             if self._debug: self._logger.log("DEBUG: starting emerge sync")
  482.             exitstatus = GLIUtility.spawn("emerge sync", chroot=self._chroot_dir, display_on_tty8=True, logfile=self._compile_logfile, append_log=True)
  483.             if not GLIUtility.exitsuccess(exitstatus):
  484.                 self._logger.log("ERROR!  Could not sync the portage tree using emerge sync.  Falling back to emerge-webrsync as a backup.")
  485.                 sync_type = "webrsync"
  486.             else:
  487.                 self._logger.log("Portage tree sync'd")
  488.         # If the type is webrsync, then run emerge-webrsync
  489.         elif sync_type == "webrsync":
  490.             if self._debug: self._logger.log("DEBUG: starting emerge webrsync")
  491.             exitstatus = GLIUtility.spawn("emerge-webrsync", chroot=self._chroot_dir, display_on_tty8=True, logfile=self._compile_logfile, append_log=True)
  492.             if not GLIUtility.exitsuccess(exitstatus):
  493.                 raise GLIException("EmergeWebRsyncError", 'fatal','install_portage_tree', "Failed to retrieve portage tree using webrsync!")
  494.             self._logger.log("Portage tree sync'd using webrsync")
  495.         # Otherwise, spit out a message because its probably a bad thing.
  496.         else:
  497.             self._logger.log("NOTICE!  No valid portage tree sync method was selected.  This will most likely result in a failed installation unless the tree is mounted.")
  498.             
  499.     ##
  500.     # Sets the timezone for the new environment
  501.     def set_timezone(self):
  502.         
  503.         # Set symlink
  504.         if os.access(self._chroot_dir + "/etc/localtime", os.W_OK):
  505.             if self._debug: self._logger.log("DEBUG: /etc/localtime already exists, removing it so it can be symlinked")
  506.             GLIUtility.spawn("rm "+self._chroot_dir + "/etc/localtime")
  507.         if self._debug: self._logger.log("DEBUG: running ln -s ../usr/share/zoneinfo/" + self._install_profile.get_time_zone() + " /etc/localtime")
  508.         GLIUtility.spawn("ln -s ../usr/share/zoneinfo/" + self._install_profile.get_time_zone() + " /etc/localtime", chroot=self._chroot_dir)
  509.         if not (self._install_profile.get_time_zone() == "UTC"):
  510.             if self._debug: self._logger.log("DEBUG: timezone was not UTC, setting CLOCK to local.  This may be overwritten later.")
  511.             self._edit_config(self._chroot_dir + "/etc/conf.d/clock", {"CLOCK":"local"})
  512.         self._logger.log("Timezone set.")
  513.         
  514.     ##
  515.     # Configures /etc/fstab on the new envorinment 
  516.     def configure_fstab(self):
  517.         newfstab = ""
  518.         parts = self._install_profile.get_partition_tables()
  519.         for device in parts:
  520.             tmp_partitions = parts[device].get_install_profile_structure()
  521.             for partition in tmp_partitions:
  522.                 mountpoint = tmp_partitions[partition]['mountpoint']
  523.                 minor = str(int(tmp_partitions[partition]['minor']))
  524.                 partition_type = tmp_partitions[partition]['type']
  525.                 mountopts = tmp_partitions[partition]['mountopts']
  526.                 if not mountopts.strip(): mountopts = "defaults"
  527.                 if mountpoint:
  528.                     if not GLIUtility.is_file(self._chroot_dir+mountpoint):
  529.                         if self._debug: self._logger.log("DEBUG: making mountpoint: "+mountpoint)
  530.                         exitstatus = GLIUtility.spawn("mkdir -p " + self._chroot_dir + mountpoint)
  531.                         if not GLIUtility.exitsuccess(exitstatus):
  532.                             raise GLIException("MkdirError", 'fatal','configure_fstab', "Making the mount point failed!")
  533.                     newfstab += device+minor+"\t "+mountpoint+"\t "+partition_type+"\t "+mountopts+"\t\t "
  534.                     if mountpoint == "/boot":
  535.                         newfstab += "1 2\n"
  536.                     elif mountpoint == "/":
  537.                         newfstab += "0 1\n"
  538.                     else:
  539.                         newfstab += "0 0\n"
  540.                 if partition_type == "linux-swap":
  541.                     newfstab += device+minor+"\t none            swap            sw              0 0\n"
  542.         newfstab += "none        /proc     proc    defaults          0 0\n"
  543.         newfstab += "none        /dev/shm  tmpfs   defaults          0 0\n"
  544.         if GLIUtility.is_device("/dev/cdrom"):
  545.             newfstab += "/dev/cdrom    /mnt/cdrom    auto      noauto,user    0 0\n"
  546.  
  547.         for netmount in self._install_profile.get_network_mounts():
  548.             if netmount['type'] == "nfs":
  549.                 newfstab += netmount['host'] + ":" + netmount['export'] + "\t" + netmount['mountpoint'] + "\tnfs\t" + netmount['mountopts'] + "\t0 0\n"
  550.             
  551.         file_name = self._chroot_dir + "/etc/fstab"    
  552.         try:
  553.             if self._debug: self._logger.log("DEBUG: backing up original fstab")
  554.             shutil.move(file_name, file_name + ".OLDdefault")
  555.         except:
  556.             self._logger.log("ERROR: could not backup original fstab.")
  557.         if self._debug: self._logger.log("DEBUG: Contents of new fstab: "+newfstab)
  558.         f = open(file_name, 'w')
  559.         f.writelines(newfstab)
  560.         f.close()
  561.         self._logger.log("fstab configured.")
  562.  
  563.     ##
  564.     # Fetches desired kernel sources, unless you're using a livecd-kernel in which case it does freaky stuff.
  565.     def emerge_kernel_sources(self):
  566.         self._logger.log("Starting emerge_kernel")
  567.         kernel_pkg = self._install_profile.get_kernel_source_pkg()
  568. #        if kernel_pkg:
  569.         # Special case, no kernel installed
  570.         if kernel_pkg == "none":
  571.             return
  572.         # Special case, livecd kernel
  573.         elif kernel_pkg == "livecd-kernel":
  574.             if self._debug: self._logger.log("DEBUG: starting livecd-kernel setup")
  575.             self.notify_frontend("progress", (0, "Copying livecd-kernel to chroot"))
  576. #            self._portage.copy_pkg_to_chroot(self._portage.get_best_version_vdb("livecd-kernel"))
  577.             self.notify_frontend("progress", (1, "Done copying livecd-kernel to chroot"))
  578.  
  579. #            exitstatus = self._portage.emerge("coldplug")
  580. #            self._logger.log("Coldplug emerged.  Now they should be added to the boot runlevel.")
  581. #            self._add_to_runlevel("coldplug", runlevel="boot")
  582.  
  583.             # Extra modules from kernelpkgs.txt...disabled until I can figure out why it sucks
  584. #            try:
  585. #                kernpkgs = open("/usr/livecd/kernelpkgs.txt", "r")
  586. #                pkgs = ""
  587. #                for line in kernpkgs.readlines():
  588. #                    pkgs += line.strip() + " "
  589. #                kernpkgs.close()
  590. #            except:
  591. #                raise GLIException("EmergeColdplugError", 'fatal','build_kernel', "Could not read kernelpkgs.txt")
  592. #            exitstatus = self._emerge(pkgs)
  593. #            if not GLIUtility.exitsuccess(exitstatus):
  594. #                raise GLIException("EmergeExtraKernelModulesError", 'fatal','build_kernel', "Could not emerge extra kernel packages")
  595. #            self._logger.log("Extra kernel packages emerged.")
  596.  
  597.         # normal case
  598.         else:
  599.             exitstatus = self._portage.emerge(kernel_pkg)
  600. #            if not GLIUtility.exitsuccess(exitstatus):
  601. #                raise GLIException("EmergeKernelSourcesError", 'fatal','emerge_kernel_sources',"Could not retrieve kernel sources!")
  602.             try:
  603.                 os.stat(self._chroot_dir + "/usr/src/linux")
  604.             except:
  605.                 kernels = os.listdir(self._chroot_dir+"/usr/src")
  606.                 if self._debug: self._logger.log("DEBUG: no /usr/src/linux found.  found kernels: "+kernels)
  607.                 found_a_kernel = False
  608.                 counter = 0
  609.                 while not found_a_kernel:
  610.                     if kernels[counter][0:6]=="linux-":
  611.                         if self._debug: self._logger.log("DEBUG: found one.  linking it. running: ln -s /usr/src/"+kernels[counter]+ " /usr/src/linux in the chroot.")
  612.                         exitstatus = GLIUtility.spawn("ln -s /usr/src/"+kernels[counter]+ " /usr/src/linux",chroot=self._chroot_dir)
  613.                         if not GLIUtility.exitsuccess(exitstatus):
  614.                             raise GLIException("EmergeKernelSourcesError", 'fatal','emerge_kernel_sources',"Could not make a /usr/src/linux symlink")
  615.                         found_a_kernel = True
  616.                     else:
  617.                         counter = counter + 1
  618.             self._logger.log("Kernel sources:"+kernel_pkg+" emerged and /usr/src/linux symlinked.")
  619.  
  620.     ##
  621.     # Builds the kernel using genkernel or regularly if given a custom .config file in the profile
  622.     def build_kernel(self):
  623.         self._logger.mark()
  624.         self._logger.log("Starting build_kernel")
  625.  
  626.         build_mode = self._install_profile.get_kernel_build_method()
  627.  
  628.         # No building necessary if using the LiveCD's kernel/initrd
  629.         # or using the 'none' kernel bypass
  630.         if self._install_profile.get_kernel_source_pkg() in ["livecd-kernel","none"]:
  631.             if self._debug: self._logger.log("DEBUG: using "+self._install_profile.get_kernel_source_pkg()+ " so skipping this function.")        
  632.             return
  633.         # Get the uri to the kernel config
  634.         kernel_config_uri = self._install_profile.get_kernel_config_uri()
  635.  
  636.         # is there an easier way to do this?
  637.         if self._debug: self._logger.log("DEBUG: running command: awk '/^PATCHLEVEL/{print $3}' /usr/src/linux/Makefile in chroot.")
  638.         ret, kernel_major = GLIUtility.spawn("awk '/^PATCHLEVEL/{print $3}' /usr/src/linux/Makefile",chroot=self._chroot_dir,return_output=True)
  639.         # 6 == 2.6 kernel, 4 == 2.4 kernel
  640.         kernel_major = int(kernel_major)
  641.         if self._debug: self._logger.log("DEBUG: kernel major version is: "+str(kernel_major))
  642.         #Copy the kernel .config to the proper location in /usr/src/linux
  643.         if kernel_config_uri != '':
  644.             try:
  645.                 if self._debug: self._logger.log("DEBUG: grabbing kernel config from "+kernel_config_uri+" and putting it in "+self._chroot_dir + "/var/tmp/kernel_config")
  646.                 GLIUtility.get_uri(kernel_config_uri, self._chroot_dir + "/var/tmp/kernel_config")
  647.             except:
  648.                 raise GLIException("KernelBuildError", 'fatal', 'build_kernel', "Could not copy kernel config!")
  649.             
  650.         # the && stuff is important so that we can catch any errors.
  651.         kernel_compile_script =  "#!/bin/bash\n"
  652.         kernel_compile_script += "cp /var/tmp/kernel_config /usr/src/linux/.config && "
  653.         kernel_compile_script += "cd /usr/src/linux && "
  654.         # required for 2.[01234] etc kernels
  655.         if kernel_major in [0,1,2,3,4]:
  656.             kernel_compile_script += " yes 'n' | make oldconfig && make symlinks && make dep"
  657.         # not strictly needed, but recommended by upstream
  658.         else: #elif kernel_major in [5,6]:
  659.             kernel_compile_script += "make prepare"
  660.         
  661.         # bypass to install a kernel, but not compile it
  662.         if build_mode == "none":
  663.             return
  664.         # this mode is used to install kernel sources, and have then configured
  665.         # but not actually build the kernel. This is needed for netboot
  666.         # situations when you have packages that require kernel sources
  667.         # to build.
  668.         elif build_mode == "prepare-only":
  669.             if self._debug: self._logger.log("DEBUG: writing kernel script with contents: "+kernel_compile_script)
  670.             f = open(self._chroot_dir+"/var/tmp/kernel_script", 'w')
  671.             f.writelines(kernel_compile_script)
  672.             f.close()
  673.             #Build the kernel
  674.             if self._debug: self._logger.log("DEBUG: running: chmod u+x "+self._chroot_dir+"/var/tmp/kernel_script")
  675.             exitstatus1 = GLIUtility.spawn("chmod u+x "+self._chroot_dir+"/var/tmp/kernel_script")
  676.             if self._debug: self._logger.log("DEBUG: running: /var/tmp/kernel_script in chroot.")
  677.             exitstatus2 = GLIUtility.spawn("/var/tmp/kernel_script", chroot=self._chroot_dir, display_on_tty8=True, logfile=self._compile_logfile, append_log=True)
  678.             if not GLIUtility.exitsuccess(exitstatus1):
  679.                 raise GLIException("KernelBuildError", 'fatal', 'build_kernel', "Could not handle prepare-only build! died on chmod.")
  680.             if not GLIUtility.exitsuccess(exitstatus2):
  681.                 raise GLIException("KernelBuildError", 'fatal', 'build_kernel', "Could not handle prepare-only build! died on running of kernel script.")
  682.             #i'm sure i'm forgetting something here.
  683.             #cleanup
  684.             exitstatus = GLIUtility.spawn("rm -f "+self._chroot_dir+"/var/tmp/kernel_script "+self._chroot_dir+"/var/tmp/kernel_config")
  685.             #it's not important if this fails.
  686.             self._logger.log("prepare-only build complete")
  687.         # Genkernel mode, including custom kernel_config. Initrd always on.
  688.         elif build_mode == "genkernel":
  689.             if self._debug: self._logger.log("DEBUG: build_kernel(): starting emerge genkernel")        
  690.             exitstatus = self._portage.emerge("genkernel")
  691. #            if not GLIUtility.exitsuccess(exitstatus):
  692. #                raise GLIException("EmergeGenKernelError", 'fatal','build_kernel', "Could not emerge genkernel!")
  693.             self._logger.log("Genkernel emerged.  Beginning kernel compile.")
  694.             # Null the genkernel_options
  695.             genkernel_options = ""
  696.     
  697.             # If the uri for the kernel config is not null, then
  698.             if kernel_config_uri != "":
  699.                 if self._debug: self._logger.log("DEBUG: build_kernel(): getting kernel config "+kernel_config_uri)
  700.                 GLIUtility.get_uri(kernel_config_uri, self._chroot_dir + "/var/tmp/kernel_config")
  701.                 genkernel_options = genkernel_options + " --kernel-config=/var/tmp/kernel_config"
  702.                 
  703.             # Decide whether to use bootsplash or not
  704.             if self._install_profile.get_kernel_bootsplash():
  705.                 genkernel_options = genkernel_options + " --gensplash"
  706.             else:
  707.                 genkernel_options = genkernel_options + " --no-gensplash"
  708.             # Run genkernel in chroot
  709.             #print "genkernel all " + genkernel_options
  710.             if self._debug: self._logger.log("DEBUG: build_kernel(): running: genkernel all " + genkernel_options + " in chroot.")
  711.             exitstatus = GLIUtility.spawn("genkernel all " + genkernel_options, chroot=self._chroot_dir, display_on_tty8=True, logfile=self._compile_logfile, append_log=True)
  712.             if not GLIUtility.exitsuccess(exitstatus):
  713.                 raise GLIException("KernelBuildError", 'fatal', 'build_kernel', "Could not build kernel!")
  714.             
  715. #            exitstatus = self._emerge("hotplug")
  716. #            if not GLIUtility.exitsuccess(exitstatus):
  717. #                raise GLIException("EmergeHotplugError", 'fatal','build_kernel', "Could not emerge hotplug!")
  718. #            self._logger.log("Hotplug emerged.")
  719.             exitstatus = self._portage.emerge("coldplug")
  720. #            if not GLIUtility.exitsuccess(exitstatus):
  721. #                raise GLIException("EmergeColdplugError", 'fatal','build_kernel', "Could not emerge coldplug!")
  722.             self._logger.log("Coldplug emerged.  Now they should be added to the default runlevel.")
  723.             
  724. #            self._add_to_runlevel("hotplug")
  725.             self._add_to_runlevel("coldplug", runlevel="boot")
  726.             self._logger.log("Genkernel complete.")
  727.         elif build_mode == "custom":  #CUSTOM CONFIG
  728.             
  729.             kernel_compile_script += " && make && make modules && make modules_install"
  730.  
  731.             #Ok now that it's built, copy it to /boot/kernel-* for bootloader code to find it
  732.             if self._client_configuration.get_architecture_template() == "x86":
  733.                 kernel_compile_script += " && cp /usr/src/linux/arch/i386/boot/bzImage /boot/kernel-custom\n"
  734.             elif self._client_configuration.get_architecture_template() == "amd64":
  735.                 kernel_compile_script += " && cp /usr/src/linux/arch/x86_64/boot/bzImage /boot/kernel-custom\n"
  736.             elif self._client_configuration.get_architecture_template() == "ppc":
  737.                 kernel_compile_script += " && cp /usr/src/linux/vmlinux /boot/kernel-custom\n"
  738.             if self._debug: self._logger.log("DEBUG: build_kernel(): writing custom kernel script: "+kernel_compile_script)
  739.             f = open(self._chroot_dir+"/var/tmp/kernel_script", 'w')
  740.             f.writelines(kernel_compile_script)
  741.             f.close()
  742.             #Build the kernel
  743.             if self._debug: self._logger.log("DEBUG: build_kernel(): running: chmod u+x "+self._chroot_dir+"/var/tmp/kernel_script")
  744.             exitstatus1 = GLIUtility.spawn("chmod u+x "+self._chroot_dir+"/var/tmp/kernel_script")
  745.             if self._debug: self._logger.log("DEBUG: build_kernel(): running: /var/tmp/kernel_script in chroot")
  746.             exitstatus2 = GLIUtility.spawn("/var/tmp/kernel_script", chroot=self._chroot_dir, display_on_tty8=True, logfile=self._compile_logfile, append_log=True)
  747.             if not GLIUtility.exitsuccess(exitstatus1):
  748.                 raise GLIException("KernelBuildError", 'fatal', 'build_kernel', "Could not build custom kernel! died on chmod.")
  749.             if not GLIUtility.exitsuccess(exitstatus2):
  750.                 raise GLIException("KernelBuildError", 'fatal', 'build_kernel', "Could not build custom kernel! died on running of kernel script.")
  751.                         
  752.             #i'm sure i'm forgetting something here.
  753.             #cleanup
  754.             exitstatus = GLIUtility.spawn("rm -f "+self._chroot_dir+"/var/tmp/kernel_script "+self._chroot_dir+"/var/tmp/kernel_config")
  755.             #it's not important if this fails.
  756.             self._logger.log("Custom kernel complete")
  757.             
  758.     ##
  759.     # Installs and starts up distccd if the user has it set, so that it will get used for the rest of the install
  760.     def install_distcc(self):
  761.         if self._install_profile.get_install_distcc():
  762.             if self._debug: self._logger.log("DEBUG: install_distcc(): we ARE installing distcc")
  763.             if self._debug: self._logger.log("DEBUG: install_distcc(): running: USE='-*' emerge --nodeps sys-devel/distcc in chroot.")
  764.             exitstatus = GLIUtility.spawn("USE='-*' emerge --nodeps sys-devel/distcc", chroot=self._chroot_dir, display_on_tty8=True, logfile=self._compile_logfile, append_log=True)
  765.             if not GLIUtility.exitsuccess(exitstatus):
  766.                 self._logger.log("ERROR! : Could not emerge distcc!")
  767.             else:
  768.                 self._logger.log("distcc emerged.")    
  769.     
  770.     ##
  771.     # Installs mail MTA. Does not put into runlevel, as this is not simple with MTAs.
  772.     def install_mta(self):
  773.         # Get MTA info
  774.         mta_pkg = self._install_profile.get_mta_pkg()
  775.         if mta_pkg:
  776.             # Emerge MTA
  777.             if self._debug: self._logger.log("DEBUG: install_mta(): installing mta: "+mta_pkg)
  778.             exitstatus = self._portage.emerge(mta_pkg)
  779. #            if not GLIUtility.exitsuccess(exitstatus):
  780. #                raise GLIException("MTAError", 'fatal','install_mta', "Could not emerge " + mta_pkg + "!")
  781.             self._logger.log("MTA installed: "+mta_pkg)
  782.  
  783.     ##
  784.     # Installs and sets up logging daemon on the new system.  adds to runlevel too.
  785.     def install_logging_daemon(self):
  786.         # Get loggin daemon info
  787.         logging_daemon_pkg = self._install_profile.get_logging_daemon_pkg()
  788.         if logging_daemon_pkg:
  789.             # Emerge Logging Daemon
  790.             if self._debug: self._logger.log("DEBUG: install_logging_daemon: emerging "+logging_daemon_pkg)
  791.             exitstatus = self._portage.emerge(logging_daemon_pkg)
  792. #            if not GLIUtility.exitsuccess(exitstatus):
  793. #                raise GLIException("LoggingDaemonError", 'fatal','install_logging_daemon', "Could not emerge " + logging_daemon_pkg + "!")
  794.  
  795.             # Add Logging Daemon to default runlevel
  796.             # After we find the name of it's initscript
  797.             # This current code is a hack, and should be better.
  798.             initscript = logging_daemon_pkg[(logging_daemon_pkg.find('/')+1):]
  799.             if self._debug: self._logger.log("DEBUG: install_logging_daemon: adding "+initscript+" to runlevel")
  800.             self._add_to_runlevel(initscript)
  801.             self._logger.log("Logging daemon installed: "+logging_daemon_pkg)
  802.     ##
  803.     # Installs and sets up cron package.
  804.     def install_cron_daemon(self):
  805.         # Get cron daemon info
  806.         cron_daemon_pkg = self._install_profile.get_cron_daemon_pkg()
  807.         if cron_daemon_pkg:
  808.             if cron_daemon_pkg == "none":
  809.                 self._logger.log("Skipping installation of cron daemon")
  810.             else:
  811.                 # Emerge Cron Daemon
  812.                 if self._debug: self._logger.log("DEBUG: install_cron_daemon: emerging "+cron_daemon_pkg)
  813.                 exitstatus = self._portage.emerge(cron_daemon_pkg)
  814. #                if not GLIUtility.exitsuccess(exitstatus):
  815. #                    raise GLIException("CronDaemonError", 'fatal', 'install_cron_daemon', "Could not emerge " + cron_daemon_pkg + "!")
  816.  
  817.                 # Add Cron Daemon to default runlevel
  818.                 # After we find the name of it's initscript
  819.                 # This current code is a hack, and should be better.
  820.                 initscript = cron_daemon_pkg[(cron_daemon_pkg.find('/')+1):]
  821.                 if self._debug: self._logger.log("DEBUG: install_cron_daemon: adding "+initscript+" to runlevel")
  822.                 self._add_to_runlevel(initscript)
  823.  
  824.                 # If the Cron Daemon is not vixie-cron, run crontab            
  825.                 if "vixie-cron" not in cron_daemon_pkg:
  826.                     if self._debug: self._logger.log("DEBUG: install_cron_daemon: running: crontab /etc/crontab in chroot.")
  827.                     exitstatus = GLIUtility.spawn("crontab /etc/crontab", chroot=self._chroot_dir, display_on_tty8=True)
  828.                     if not GLIUtility.exitsuccess(exitstatus):
  829.                         raise GLIException("CronDaemonError", 'fatal', 'install_cron_daemon', "Failure making crontab!")
  830.                 self._logger.log("Cron daemon installed and configured: "+cron_daemon_pkg)
  831.     
  832.     ##
  833.     # This will parse the partitions looking for types that require fstools and emerge them if found.
  834.     def install_filesystem_tools(self):
  835.         "Installs and sets up fstools"
  836.         # Get the list of file system tools to be installed
  837.         parts = self._install_profile.get_partition_tables()
  838.         # don't use an array, use a set instead
  839.         filesystem_types = {}
  840.         for device in parts:
  841.             tmp_partitions = parts[device].get_install_profile_structure()
  842.             for partition in tmp_partitions:
  843.                 partition_type = tmp_partitions[partition]['type'].lower()
  844.                 if partition_type not in filesystem_types:
  845.                     filesystem_types[partition_type] = None
  846.  
  847.         package_list = []
  848.         for filesystem in filesystem_types.keys():
  849.             if filesystem == 'xfs':
  850.                 package_list.append('sys-fs/xfsprogs')
  851.             elif filesystem == 'reiserfs':
  852.                 package_list.append('sys-fs/reiserfsprogs')
  853.             elif filesystem == 'jfs':
  854.                 package_list.append('sys-fs/jfsutils')
  855.             elif filesystem == 'ntfs':
  856.                 package_list.append('sys-fs/ntfsprogs')
  857.             elif filesystem in ['fat','vfat', 'msdos', 'umsdos']:
  858.                 package_list.append('sys-fs/dosfstools')
  859.             elif filesystem == 'hfs':
  860.                 # should check with the PPC guys on this
  861.                 package_list.append('sys-fs/hfsutils')
  862.                 package_list.append('sys-fs/hfsplusutils')
  863.             #else:
  864.             # should be code here for every FS type!
  865.         failed_list = []
  866. #        for package in package_list:
  867. #            if self._debug: self._logger.log("DEBUG: install_filesystem_tools(): emerging "+package)
  868. #            exitstatus = self._portage.emerge(package)
  869. #            if not GLIUtility.exitsuccess(exitstatus):
  870. #                self._logger.log("ERROR! : Could not emerge "+package+"!")
  871. #                failed_list.append(package)
  872. #            else:
  873. #        self._logger.log("FileSystemTool "+package+" was emerged successfully.")
  874.         # error checking is important!
  875.         if len(failed_list) > 0:
  876.             raise GLIException("InstallFileSystemToolsError", 'warning', 'install_filesystem_tools', "Could not emerge " + failed_list + "!")
  877.                     
  878.     ##
  879.     # Installs rp-pppoe but does not configure it.  This function is quite the unknown.
  880.     def install_rp_pppoe(self):
  881.         # If user wants us to install rp-pppoe, then do so
  882.         if self._install_profile.get_install_rp_pppoe():
  883.             if self._debug: self._logger.log("DEBUG: install_rp_pppoe: emerging rp-pppoe")
  884.             exitstatus = self._portage.emerge("rp-pppoe")
  885. #            if not GLIUtility.exitsuccess(exitstatus):
  886. #                self._logger.log("ERROR! : Could not emerge rp-pppoe!")
  887.             #    raise GLIException("RP_PPPOEError", 'warning', 'install_rp_pppoe', "Could not emerge rp-pppoe!")
  888. #            else:
  889.             self._logger.log("rp-pppoe emerged but not set up.")    
  890.         # Should we add a section here to automatically configure rp-pppoe?
  891.         # I think it should go into the setup_network_post section
  892.         # What do you guys think? <-- said by unknown. samyron or npmcallum
  893.                 
  894.     ##
  895.     # Installs and sets up pcmcia-cs if selected in the profile
  896.     def install_pcmcia_cs(self):
  897.         if self._debug: self._logger.log("DEBUG: install_pcmcia_cs(): emerging pcmcia-cs")
  898.         exitstatus = self._portage.emerge("pcmcia-cs")
  899. #        if not GLIUtility.exitsuccess(exitstatus):
  900. #            self._logger.log("ERROR! : Could not emerge pcmcia-cs!")
  901.             
  902.         # Add pcmcia-cs to the default runlevel
  903. #        else:
  904.         self._add_to_runlevel('pcmcia')
  905.         self._logger.log("PCMCIA_CS emerged and configured.")
  906.             
  907.     ##
  908.     # This runs etc-update and then re-overwrites the files by running the configure_*'s to keep our values.
  909.     def update_config_files(self):
  910.         "Runs etc-update (overwriting all config files), then re-configures the modified ones"
  911.         # Run etc-update overwriting all config files
  912.         if self._debug: self._logger.log("DEBUG: update_config_files(): running: "+'echo "-5" | chroot '+self._chroot_dir+' etc-update')
  913.         status = GLIUtility.spawn('echo "-5" | chroot '+self._chroot_dir+' etc-update', display_on_tty8=True, logfile=self._compile_logfile, append_log=True)
  914.         if not GLIUtility.exitsuccess(status):
  915.             self._logger.log("ERROR! : Could not update the config files!")
  916.         else:    
  917. #            self.configure_make_conf()
  918.             self.configure_fstab()
  919. #            self.configure_rc_conf()
  920.             etc_files = self._install_profile.get_etc_files()
  921.             for etc_file in etc_files:
  922.                 if self._debug: self._logger.log("DEBUG: update_config_files(): updating config file: "+etc_file)
  923.                 if isinstance(etc_files[etc_file], dict):
  924.                     self._edit_config(self._chroot_dir + "/etc/" + etc_file, etc_files[etc_file])
  925.                 else:
  926.                     for entry in etc_files[etc_file]:
  927.                         self._edit_config(self._chroot_dir + "/etc/" + etc_file, { "0": entry }, only_value=True)
  928.             self._logger.log("Config files updated using etc-update.  make.conf/fstab/rc.conf restored.")
  929.  
  930.     ##
  931.     # Configures /etc/rc.conf (deprecated by above code)
  932.     def configure_rc_conf(self):
  933.         
  934.         # Get make.conf options
  935.         options = self._install_profile.get_rc_conf()
  936.         
  937.         # For each configuration option...
  938.         filename = self._chroot_dir + "/etc/rc.conf"
  939. #        self._edit_config(filename, {"COMMENT": "GLI additions ===>"})
  940.         for key in options.keys():
  941.             # Add/Edit it into rc.conf
  942.             self._edit_config(filename, {key: options[key]})
  943. #        self._edit_config(filename, {"COMMENT": "<=== End GLI additions"})
  944.         self._logger.log("rc.conf configured.")
  945.         
  946.     ##
  947.     # Sets up the network for the first boot
  948.     def setup_network_post(self):
  949.         if self._debug: self._logger.log("DEBUG: setup_network_post(): starting network configuration")
  950.         # Get hostname, domainname and nisdomainname
  951.         hostname = self._install_profile.get_hostname()
  952.         domainname = self._install_profile.get_domainname()
  953.         nisdomainname = self._install_profile.get_nisdomainname()
  954.         
  955.         # Write the hostname to the hostname file        
  956.         #open(self._chroot_dir + "/etc/hostname", "w").write(hostname + "\n")
  957.         self._edit_config(self._chroot_dir + "/etc/conf.d/hostname", {"HOSTNAME": hostname})
  958.         
  959.         # Write the domainname to the nisdomainname file
  960.         if domainname:
  961.             #open(self._chroot_dir + "/etc/dnsdomainname", "w").write(domainname + "\n")
  962.             self._edit_config(self._chroot_dir + "/etc/conf.d/domainname", {"DNSDOMAIN": domainname})
  963.             self._add_to_runlevel("domainname")
  964.         
  965.         # Write the nisdomainname to the nisdomainname file
  966.         if nisdomainname:
  967.             #open(self._chroot_dir + "/etc/nisdomainname", "w").write(nisdomainname + "\n")
  968.             self._edit_config(self._chroot_dir + "/etc/conf.d/domainname", {"NISDOMAIN": nisdomainname})
  969.             self._add_to_runlevel("domainname")
  970.             
  971.         #
  972.         # EDIT THE /ETC/HOSTS FILE
  973.         #
  974.             
  975.         # The address we are editing is 127.0.0.1
  976.         hosts_ip = "127.0.0.1"
  977.  
  978.         # If the hostname is localhost
  979.         if hostname == "localhost":
  980.             # If a domainname is set
  981.             if domainname:
  982.                 hosts_line = hostname + "." + domainname + "\t" + hostname
  983.             else:
  984.                 hosts_line = hostname
  985.         # If the hostname is not localhost
  986.         else:
  987.             # If a domainname is set
  988.             if domainname:
  989.                 hosts_line = hostname + "." + domainname + "\t" + hostname + "\tlocalhost"
  990.             else:
  991.                 hosts_line = "localhost\t" + hostname
  992.  
  993.         # Write to file
  994.         self._edit_config(self._chroot_dir + "/etc/hosts", {hosts_ip: hosts_line}, delimeter='\t', quotes_around_value=False)
  995.  
  996.         #
  997.         # SET DEFAULT GATEWAY
  998.         #
  999.  
  1000.         # Get default gateway
  1001.         default_gateway = self._install_profile.get_default_gateway()
  1002.         
  1003.         # If the default gateway exists, add it
  1004.         if default_gateway:
  1005.             default_gateway_string = default_gateway[0] + "/" + default_gateway[1]
  1006.             if self._debug: self._logger.log("DEBUG: setup_network_post(): found gateway. adding to confing. "+default_gateway_string)
  1007.             self._edit_config(self._chroot_dir + "/etc/conf.d/net", {"gateway": default_gateway_string})
  1008.             
  1009.         #
  1010.         # SET RESOLV INFO
  1011.         #
  1012.  
  1013.         # Get dns servers
  1014.         dns_servers = self._install_profile.get_dns_servers()
  1015.         
  1016.         # Clear the list
  1017.         resolv_output = []
  1018.         
  1019.         # If dns servers are set
  1020.         if dns_servers:
  1021.             
  1022.             
  1023.             # Parse each dns server
  1024.             for dns_server in dns_servers:
  1025.                 # Add the server to the output
  1026.                 resolv_output.append("nameserver " + dns_server +"\n")
  1027.             
  1028.             # If the domainname is set, then also output it
  1029.             if domainname:
  1030.                 resolv_output.append("search " + domainname + "\n")
  1031.                 
  1032.             # Output to file
  1033.             if self._debug: self._logger.log("DEBUG: setup_network_post(): writing resolv.conf with contents: "+resolv_output)
  1034.             resolve_conf = open(self._chroot_dir + "/etc/resolv.conf", "w")
  1035.             resolve_conf.writelines(resolv_output)
  1036.             resolve_conf.close()
  1037.         
  1038.         #
  1039.         # PARSE INTERFACES
  1040.         #
  1041.  
  1042.         # Fetch interfaces
  1043.         interfaces = self._install_profile.get_network_interfaces()
  1044.         emerge_dhcp = False
  1045.         # Parse each interface
  1046.         for interface in interfaces.keys():
  1047.             if self._debug: self._logger.log("DEBUG: setup_network_post(): configuring interface: "+ interface)
  1048.             # Set what kind of interface it is
  1049.             interface_type = interface[:3]
  1050.         
  1051.             # Check to see if there is a startup script for this interface, if there isn't link to the proper script
  1052.             try:
  1053.                 os.stat(self._chroot_dir + "/etc/init.d/net." + interface)
  1054.             except:
  1055.                 if self._debug: self._logger.log("DEBUG: setup_network_post(): /etc/init.d/net." + interface + " didn't exist, symlinking it.")
  1056.                 os.symlink("net." + interface_type +  "0", self._chroot_dir + "/etc/init.d/net." + interface)
  1057.         
  1058.             # If we are going to load the network at boot...
  1059.             #if interfaces[interface][2]:  #THIS FEATURE NO LONGER EXISTS
  1060.                 
  1061.             # Add it to the default runlevel
  1062.             if self._debug: self._logger.log("DEBUG: setup_network_post(): adding net."+interface+" to runlevel.")
  1063.             self._add_to_runlevel("net."+interface)    # moved a bit <-- for indentation
  1064.  
  1065.             #
  1066.             # ETHERNET
  1067.             #
  1068.             if interface_type == "eth":
  1069.  
  1070.                 #
  1071.                 # STATIC IP
  1072.                 #
  1073.                 # If the post-install device info is not None, then it is a static ip addy
  1074.                 if interfaces[interface][0] != "dhcp":
  1075.                     ip = interfaces[interface][0]
  1076.                     broadcast = interfaces[interface][1]
  1077.                     netmask = interfaces[interface][2]
  1078.             #        aliases = interfaces[interface][1][3]
  1079.             #        alias_ips = []
  1080.             #        alias_broadcasts = []
  1081.             #        alias_netmasks = []
  1082.                     
  1083.                     # Write the static ip config to /etc/conf.d/net
  1084.                     self._edit_config(self._chroot_dir + "/etc/conf.d/net", {"iface_" + interface: ip + " broadcast " + broadcast + " netmask " + netmask})
  1085.                     
  1086.                     # If aliases are set
  1087.             #        if aliases:
  1088.                     
  1089.                         # Parse aliases to format alias info
  1090.             #            for alias in aliases:
  1091.             #                alias_ips.append(alias[0])
  1092.             #                alias_broadcasts.append(alias[1])
  1093.             #                alias_netmasks.append(allias[2])
  1094.                         
  1095.                         # Once the alias info has been gathered, then write it out
  1096.                         # Alias ips first
  1097.             #            self._edit_config(self._chroot_dir + "/etc/conf.d/net", "alias_" + interface, string.join(alias_ips))
  1098.                         # Alias broadcasts next
  1099.             #            self._edit_config(self._chroot_dir + "/etc/conf.d/net", "broadcast_" + interface, string.join(alias_broadcasts))
  1100.                         # Alias netmasks last
  1101.             #            self._edit_config(self._chroot_dir + "/etc/conf.d/net", "netmask_" + interface, string.join(alias_netmasks))
  1102.  
  1103.                 #
  1104.                 # DHCP IP
  1105.                 #
  1106.                 else:
  1107.                     dhcpcd_options = interfaces[interface][1]
  1108.                     if not dhcpcd_options:
  1109.                         dhcpcd_options = ""
  1110.                     self._edit_config(self._chroot_dir + "/etc/conf.d/net", {"iface_" + interface: "dhcp", "dhcpcd_" + interface: dhcpcd_options})
  1111.                     emerge_dhcp = False
  1112.         if emerge_dhcp:
  1113.             if self._debug: self._logger.log("DEBUG: setup_network_post(): emerging dhcpcd.")
  1114.             exitstatus = self._portage.emerge("dhcpcd")
  1115. #            if not GLIUtility.exitsuccess(exitstatus):
  1116. #                self._logger.log("ERROR! : Could not emerge dhcpcd!")
  1117. #            else:
  1118.             self._logger.log("dhcpcd emerged.")        
  1119.         
  1120.     ##
  1121.     # Sets the root password
  1122.     def set_root_password(self):
  1123.         if self._debug: self._logger.log("DEBUG: set_root_password(): running: "+ 'echo \'root:' + self._install_profile.get_root_pass_hash() + '\' | chroot '+self._chroot_dir+' chpasswd -e')
  1124.         status = GLIUtility.spawn('echo \'root:' + self._install_profile.get_root_pass_hash() + '\' | chroot '+self._chroot_dir+' chpasswd -e')
  1125.         if not GLIUtility.exitsuccess(status):
  1126.             raise GLIException("SetRootPasswordError", 'fatal', 'set_root_password', "Failure to set root password!")
  1127.         self._logger.log("Root Password set on the new system.")
  1128.         
  1129.     ##
  1130.     # Sets up the new users for the system
  1131.     def set_users(self):
  1132.         # Loop for each user
  1133.         for user in self._install_profile.get_users():
  1134.         
  1135.             # Get values from the tuple
  1136.             username = user[0]
  1137.             password_hash = user[1]
  1138.             groups = user[2]
  1139.             shell = user[3]
  1140.             home_dir = user[4]
  1141.             uid = user[5]
  1142.             comment = user[6]
  1143.             
  1144.             options = [ "-m", "-p '" + password_hash + "'" ]
  1145.             
  1146.             # If the groups are specified
  1147.             if groups:
  1148.             
  1149.                 # If just one group is listed as a string, make it a list
  1150.                 if groups == str:
  1151.                     groups = [ groups ]
  1152.                     
  1153.                 # If only 1 group is listed
  1154.                 if len(groups) == 1:
  1155.                     options.append("-G " + groups[0])
  1156.                     
  1157.                 # If there is more than one group
  1158.                 elif len(groups) > 1:
  1159.                     options.append('-G "' + string.join(groups, ",") + '"')
  1160.                     
  1161.                 # Attempt to add the group (will return success when group exists)
  1162.                 for group in groups:
  1163.                     # Add the user
  1164.                     if self._debug: self._logger.log("DEBUG: set_users(): adding user to groups with (in chroot): "+'groupadd -f ' + group)
  1165.                     exitstatus = GLIUtility.spawn('groupadd -f ' + group, chroot=self._chroot_dir, logfile=self._compile_logfile, append_log=True, display_on_tty8=True)
  1166.                     if not GLIUtility.exitsuccess(exitstatus):
  1167.                         self._logger.log("ERROR! : Failure to add group " + group+" and it wasn't that the group already exists!")
  1168.                     
  1169.             
  1170.             # If a shell is specified
  1171.             if shell:
  1172.                 options.append("-s " + shell)
  1173.                 
  1174.             # If a home dir is specified
  1175.             if home_dir:
  1176.                 options.append("-d " + home_dir)
  1177.                 
  1178.             # If a UID is specified
  1179.             if uid:
  1180.                 options.append("-u " + str(uid))
  1181.                 
  1182.             # If a comment is specified
  1183.             if comment:
  1184.                 options.append('-c "' + comment + '"')
  1185.                 
  1186.             # Add the user
  1187.             if self._debug: self._logger.log("DEBUG: set_users(): adding user with (in chroot): "+'useradd ' + string.join(options) + ' ' + username)
  1188.             exitstatus = GLIUtility.spawn('useradd ' + string.join(options) + ' ' + username, chroot=self._chroot_dir, logfile=self._compile_logfile, append_log=True, display_on_tty8=True)
  1189.             if not GLIUtility.exitsuccess(exitstatus):
  1190.                 self._logger.log("ERROR! : Failure to add user " + username)
  1191.             #    raise GLIException("AddUserError", 'warning', 'set_users', "Failure to add user " + username)
  1192.             else:
  1193.                 self._logger.log("User "+username+"was added.")
  1194.             
  1195.     ##
  1196.     # This function will handle the various cleanup tasks as well as unmounting the filesystems for reboot.
  1197.     def finishing_cleanup(self):
  1198.         #These are temporary until I come up with a nicer idea.
  1199.         #get rid of the compile_output file so the symlink doesn't get screwed up.
  1200.         self._add_to_runlevel("acpid")
  1201.         #we copy the log over to the new system.
  1202.         install_logfile = self._client_configuration.get_log_file()
  1203.         try:
  1204.             if self._debug: self._logger.log("DEBUG: finishing_cleanup(): copying logfile over to new system's root.")
  1205.             shutil.copy(install_logfile, self._chroot_dir + install_logfile)
  1206.         except:
  1207.             if self._debug: self._logger.log("DEBUG: finishing_cleanup(): ERROR! could not copy logfile over to /root.")
  1208.         #Now we're done logging as far as the new system is concerned.
  1209.         GLIUtility.spawn("cp /tmp/installprofile.xml " + self._chroot_dir + "/root/installprofile.xml")
  1210.         GLIUtility.spawn("cp /tmp/clientconfiguration.xml " + self._chroot_dir + "/root/clientconfiguration.xml")
  1211.         
  1212.         #Unmount mounted fileystems in preparation for reboot
  1213.         mounts = GLIUtility.spawn(r"mount | sed -e 's:^.\+ on \(.\+\) type .\+$:\1:' | grep -e '^" + self._chroot_dir + "' | sort -r", return_output=True)[1].split("\n")
  1214.         for mount in mounts:
  1215.             GLIUtility.spawn("umount -l " + mount)
  1216.             
  1217.         # now turn off all swap as well.
  1218.         # we need to find the swap devices
  1219.         for swap_device in self._swap_devices:
  1220.             ret = GLIUtility.spawn("swapoff "+swap_device)
  1221.             if not GLIUtility.exitsuccess(ret):
  1222.                 self._logger.log("ERROR! : Could not deactivate swap ("+swap_device+")!")
  1223.         
  1224.         #OLD WAY: Unmount the /proc and /dev that we mounted in prepare_chroot
  1225.         #There really isn't a reason to log errors here.
  1226.         #ret = GLIUtility.spawn("umount "+self._chroot_dir+"/proc", display_on_tty8=True, logfile=self._compile_logfile, append_log=True)
  1227.         #ret = GLIUtility.spawn("umount "+self._chroot_dir+"/dev", display_on_tty8=True, logfile=self._compile_logfile, append_log=True)
  1228.         #temp hack to unmount the new root.
  1229.         #ret = GLIUtility.spawn("umount "+self._chroot_dir, display_on_tty8=True, logfile=self._compile_logfile, append_log=True)
  1230.         #insert code here to unmount the swap partition, if there is one.
  1231.  
  1232.         GLIUtility.spawn("rm /tmp/compile_output.log && rm " + install_logfile)
  1233.         
  1234.     ##
  1235.     # This is a stub function to be done by the individual arch.  I don't think it's even needed here.
  1236.     # but it's nice having it just incase.
  1237.     def install_bootloader(self):
  1238.         "THIS FUNCTION MUST BE DONE BY THE INDIVIDUAL ARCH"
  1239.         pass
  1240.  
  1241.     def run_post_install_script(self):
  1242.         if self._install_profile.get_post_install_script_uri():
  1243.             try:
  1244.                 if self._debug: self._logger.log("DEBUG: run_post_install_script(): getting script: "+self._install_profile.get_post_install_script_uri())
  1245.                 GLIUtility.get_uri(self._install_profile.get_post_install_script_uri(), self._chroot_dir + "/var/tmp/post-install")
  1246.                 if self._debug: self._logger.log("DEBUG: run_post_install_script(): running: chmod a+x /var/tmp/post-install && /var/tmp/post-install in chroot")
  1247.                 GLIUtility.spawn("chmod a+x /var/tmp/post-install && /var/tmp/post-install", chroot=self._chroot_dir, display_on_tty8=True, logfile=self._compile_logfile, append_log=True)
  1248.             except:
  1249.                 raise GLIException("RunPostInstallScriptError", 'fatal', 'run_post_install_script', "Failed to retrieve and/or execute post-install script")
  1250.  
  1251.     ##
  1252.     # This function should only be called in the event of an install failure. It performs
  1253.     # general cleanup to prepare the system for another installer run.
  1254.     def install_failed_cleanup(self):
  1255.         if self._debug: self._logger.log("DEBUG: install_failed_cleanup(): gathering mounts to unmount")
  1256.         mounts = GLIUtility.spawn(r"mount | sed -e 's:^.\+ on \(.\+\) type .\+$:\1:' | grep -e '^" + self._chroot_dir + "' | sort -r", return_output=True)[1].split("\n")
  1257.         for mount in mounts:
  1258.             if self._debug: self._logger.log("DEBUG: install_failed_cleanup(): running: umount -l " + mount)
  1259.             GLIUtility.spawn("umount -l " + mount)
  1260.             
  1261.         # now turn off all swap as well.
  1262.         # we need to find the swap devices
  1263.         for swap_device in self._swap_devices:
  1264.             if self._debug: self._logger.log("DEBUG: install_failed_cleanup(): running: swapoff "+swap_device)
  1265.             ret = GLIUtility.spawn("swapoff "+swap_device)
  1266.             if not GLIUtility.exitsuccess(ret):
  1267.                 self._logger.log("ERROR! : Could not deactivate swap ("+swap_device+")!")
  1268.         
  1269.         if self._debug: self._logger.log("DEBUG: install_failed_cleanup(): running: cp /tmp/compile_output.log /tmp/compile_output.log.failed then removing /tmp/compile_output.log")
  1270.         GLIUtility.spawn("cp /tmp/compile_output.log /tmp/compile_output.log.failed")
  1271.         GLIUtility.spawn("rm /tmp/compile_output.log")
  1272.         GLIUtility.spawn("cp /var/log/installer.log /var/log/installer.log.failed")
  1273.         GLIUtility.spawn("rm /var/log/installer.log")
  1274.